/*
Copyright (C) 2006  Mark Garner

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

using System;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;

using CommandLine;


namespace BuildDB
{

    class BuildDB
    {

        private static string targetServerName;
        private static string targetDatabaseName;
        private static string scriptsRootDir;
        private static bool forceDatabaseDrop;

        public static int Main(string[] args)
        {

            BuildDBArguments parsedArgs = new BuildDBArguments();
            if (Parser.ParseArgumentsWithUsage(args, parsedArgs))
            {
                targetServerName = parsedArgs.targetServerName;
                targetDatabaseName = parsedArgs.targetDatabaseName;
                scriptsRootDir = parsedArgs.scriptsRootDir;
                forceDatabaseDrop = parsedArgs.forceDatabaseDrop;
            }
            else
            {
                return 1;
            }


            CreateDatabase();
            ScriptFilePlayer sfp = new ScriptFilePlayer(targetServerName, targetDatabaseName);

            try
            {
                RunSqlFileSet(sfp, "Users and Roles");
                RunSqlFileSet(sfp, "Tables");
                RunSqlFileSet(sfp, "User Defined Functions");
                RunSqlFileSet(sfp, "Views");
                RunSqlFileSet(sfp, "Stored Procedures");
                RunSqlFileSet(sfp, "Triggers");
                RunSqlFileSet(sfp, "Static Data");

                Console.WriteLine("Complete");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return 1;
            }

            return 0;
        }

        private static void RunSqlFileSet(ScriptFilePlayer sfp, string scriptType)
        {
            int numberTotalFiles = 0;
            string scriptsDir = Path.Combine(scriptsRootDir, scriptType);
            Console.WriteLine("Playing " + scriptType + " scripts...");

            if (Directory.Exists(scriptsDir))
            {

                // Gather the list of sql files in the dir 
                // This will be used to compare against to 
                // make sure that everything played into the 
                // database OK 
                foreach (string filename in Directory.GetFiles(scriptsDir))
                {
                    if (filename.ToUpper().EndsWith("SQL"))
                    {
                        numberTotalFiles++;
                    }
                }

                int numberFilesCompleted = 0;
                int numberFilesCompletedLastLoop = 0;
                Hashtable filesCompleted = new Hashtable();

                while (numberFilesCompleted < numberTotalFiles)
                {

                    //play sql scripts that have not 
                    //already been played successfully
                    foreach (string filename in Directory.GetFiles(scriptsDir))
                    {
                        if (filename.ToUpper().EndsWith("SQL"))
                        {
                            if (!filesCompleted.Contains(filename))
                            {
                                Console.Write(filename);
                                int retVal = sfp.PlayFile(filename);
                                if (retVal == 0)
                                {
                                    Console.WriteLine(", Done");
                                    filesCompleted.Add(filename, filename);
                                    numberFilesCompleted++;
                                }
                                else
                                    Console.WriteLine(", sqlcmd failed to execute file");
                            } 
                        }
                    }

                    if (numberFilesCompleted == numberFilesCompletedLastLoop)
                    {
                        throw new Exception("No progress made. Check scripts.");
                    }
                    else
                    {
                        numberFilesCompletedLastLoop = numberFilesCompleted;
                    }

                    if (numberFilesCompleted < numberTotalFiles)
                    {
                        Console.WriteLine("Taking another trip...");
                        Console.WriteLine("****************************************************");
                    }

                } //while 
                Console.WriteLine("Done With " + scriptType);
            } // directory exists 

        }

        private static int CreateDatabase()
        {

            string connString = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=master;Data Source=" + targetServerName;
            SqlConnection conn = new SqlConnection(connString);
            conn.Open();

            try
            {
                SqlCommand command;
                command = conn.CreateCommand();

                command.CommandText = "select db_id('" + targetDatabaseName + "')";
                object retVal = command.ExecuteScalar();

                //NOTE: if the database exists 
                //the database must be dropped before continuing
                if (retVal != DBNull.Value)
                {
                    //prompt the user before dropping if forceDatabaseDrop is false
                    if (!forceDatabaseDrop)
                    {
                        Console.Write("Database " + targetDatabaseName + " already exists on server " + targetServerName + ". ");
                        Console.Write("Do you want to drop database? [Y/N] ");
                        int dropDatabaseReply = Console.Read();

                        /// HACK: 89 = Y
                        if (dropDatabaseReply != 89)
                        {
                            throw new Exception("Database already exists");
                        }
                    }

                    string cmd = "ALTER DATABASE [" + targetDatabaseName + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE" + Environment.NewLine +
                                 "DROP DATABASE [" + targetDatabaseName + "]";

                    command.CommandText = cmd;
                    Console.Write("Droping database...");
                    command.ExecuteNonQuery();
                    Console.WriteLine(", done");
                }

                // create the new database 
                command = conn.CreateCommand();
                command.CommandText = "create database " + targetDatabaseName;
                Console.Write("Creating database...");
                command.ExecuteNonQuery();
                Console.WriteLine(", done");
                return 0;

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

